<?php
// 应用公共文件
use think\facade\Session;

/**
 * 数据库查询结果集无限级分类
 * @param mixed $list 结果集
 * @param string $pk 主键
 * @param string $pid 父级字段名
 * @param string $child 子结果集
 * @param int $root 起始id
 * @return @return array
 */
function list_tree($list, $pk = 'id', $pid = 'pid', $child = 'child', $root = 0)
{
    $tree = [];
    foreach ($list as $key => $val) {
        if ($val[$pid] == $root) {
            unset($list[$key]);
            if (!empty($list)) {
                $children = list_tree($list, $pk, $pid, $child, $val[$pk]);
                $val[$child] = $children;
            }
            array_push($tree, $val);
        }
    }
    return $tree;
}

function make_tree($list, $pk = 'id', $pid = 'pid', $child = 'child', $root = 0)
{
    $tree=array();
    foreach ($list as $key => $val) {
        if ($val[$pid]==$root) {
            unset($list[$key]);
            if (!empty($list)) {
                $child = make_tree($list, $pk, $pid, $child, $val[$pk]);
                if (!empty($child)) {
                    $val['child']=$child;
                } else {
                    $val['child']= array();
                }
            }
            $tree[]=$val;
        }
    }
    return $tree;
}

/**
 * 获取指定月份的第一天开始和最后一天结束的时间戳
 *
 * @param int $y 年份 $m 月份
 * @return array(本月开始时间，本月结束时间)
 */
function month_frist_and_last_day($y = "", $m = ""){
    if ($y == "") $y = date("Y");
    if ($m == "") $m = date("m");
    $m = sprintf("%02d", intval($m));
    $y = str_pad(intval($y), 4, "0", STR_PAD_RIGHT);
 
    $m>12 || $m<1 ? $m=1 : $m=$m;
    $firstday = strtotime($y . $m . "01000000");
    $firstdaystr = date("Y-m-01", $firstday);
    $lastday = strtotime(date('Y-m-d 23:59:59', strtotime("$firstdaystr +1 month -1 day")));
 
    return [ "firstday" => $firstday, "lastday" => $lastday];
}

/**
 * 生成随机字符串
 */
function generate_stochastic_string($length = 16)
{
    $permitted_chars = '0123456789abcdefghijklmnopqrstuvwxyz';
    return substr(str_shuffle($permitted_chars), 0, $length);
}

/**
 * PHP格式化字节大小
 * @param number $size      字节数
 * @param string $delimiter 数字和单位分隔符
 * @return string            格式化后的带单位的大小
 */
function format_bytes(int $size, string $delimiter = ''): string
{
    $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
    for ($i = 0; $size >= 1024 && $i < 5; $i++) {
        $size = (int) $size / 1024;
    }
    return round($size, 2) . $delimiter . $units[$i];
}

/**
 * 使用递归遍历获取文件夹的大小
 */
function get_dir_size($dirname)
{
    static $tot; //这里把$tot定义为静态的,表示$tot全局只有这一个变量
    $ds = opendir($dirname); //创建一个目录资源, 传入的目录就是资源
    while ($file = readdir($ds)) { //从目录中读取到条目
        //这里的$path 表示这个路径下的文件夹,如果不这么去定义,里边执行递归语句的时候,找不到是那个文件夹
        $path = $dirname . "/" . $file;

        //判断,如果是 . 或者 ..的目录就过滤掉
        if ($file != "." && $file != "..") {
            if (is_dir($path)) { //判断如果找到的是目录
                get_dir_size($path); //如果得到是文件夹,然后递归调用一次方法传入的$path文件夹路径就是判断得到的文件夹赋值给$dirname
            } else {
                $tot += filesize($path);
            }
        }
    }
    return $tot;
}

/**
 * 递归删除文件夹
 */
function deldir($path)
{
    //如果是目录则继续
    if (is_dir($path)) {
        //扫描一个文件夹内的所有文件夹和文件并返回数组
        $p = scandir($path);
        foreach ($p as $val) {
            //排除目录中的.和..
            if ($val != "." && $val != "..") {
                //如果是目录则递归子目录，继续操作
                if (is_dir($path . $val)) {
                    //子目录中操作删除文件夹和文件
                    deldir($path . $val . DIRECTORY_SEPARATOR);
                    //目录清空后删除空文件夹
                    @rmdir($path . $val . DIRECTORY_SEPARATOR);
                } else {
                    //如果是文件直接删除
                    unlink($path . $val);
                }
            }
        }
    }
}

/**
 * 正则匹配手机号格式
 * @param string $phone 手机号
 * @return bool
 */
function preg_phone($phone = '') {    
    $preg_phone='/^1[345789]\d{9}$/ims';
    
    return preg_match($preg_phone,$phone) ? true : false;
}

if (!function_exists('check_token')) {
    /**
     * 表单令牌验证 (从验证器里拿过来的)
     * @param array $data 
     * @param string $rule
     * @return bool 验证是否通过
     */
    function check_token($data, $rule = '__token__')
    {
        if (!isset($data[$rule]) || !Session::has($rule)) {
            // 令牌数据无效
            return false;
        }
        // 令牌验证
        if (isset($data[$rule]) && Session::get($rule) === $data[$rule]) {
            // 防止重复提交
            Session::delete($rule); // 验证完成销毁session
            return true;
        }
        // 开启TOKEN重置
        Session::delete($rule);
        return false;
    }
}